#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <map>
#include <stdlib.h>
#include <libc.h>
#include <time.h>
#include "Constantes.h"
#include "TableRoutage.h"
#include "Paquet.h"
#include "Adresse.h"

using namespace std;

//! La classe Routeur permet de définir un routeur.
/*! Un routeur est caractérisé par un numéro de port, un numéro unique permettant de s'identifier et une table de routage.
 */
class Routeur {
	
private:
    
    //! Numéro de port de la socket associé au routeur.
	int port;
    //! Numéro identification unique du routeur.
    int idRouteur;
    //! Socket du Routeur.
    int socketEcoute;
    //! Taille de l'adresse du serveur.
    socklen_t tailleAdresseServeur;
    //! Taille de l'adresse du client.
    socklen_t tailleAdresseClient;
    //! Adresse du routeur.
    struct sockaddr_in myAdresse;
    //! Adresse du client.
    struct sockaddr_in adresseClient;
    //! Adresse du serveur.
	struct sockaddr_in adresseServeur;
    //! Adresse du processus de perte.
    struct sockaddr_in adresseProcessusPerte;
	
    //! Thread permettant de gérer tous les paquets envoyés par le routeur.
	pthread_t threadEnvoie;
    //! Thread permettant de gérer tous les paquets recus par le routeur.
    pthread_t threadRecoit;
    //! Tread permettant de gérer les messages textes (entrés par l'utilisateur) envoyés par le routeur.
    pthread_t threadMessage;

    // TODO: A compléter...
	socklen_t tailleServeur;
    
    //! Table de correspondance entre les numéros des routeurs et les adresses des routeurs.
	map<int,Adresse> adressesVoisins;
    //! Table de routage du routeur.
    TableRoutage *tableRoutage;
    //! Réponse du serveur
    char reponseServeur[1024];
	map<int, int> attenteReponseVoisins;
	map<int, bool> dejaForceModifier;
    
    
public:
    
    //! Constructeur basic de la classe Routeur.
    Routeur();
    
    //! Constructeur permettant de créer un nouveau routeur avec un numéro de port.
    /*!
     \param port le numéro de port du routeur. 
     */
	Routeur(int port);
    
    //! Destructeur de la classe Routeur.
    ~Routeur();
    
    //! Initialise le routeur.
    /*!
     Initialise et lance la socket permettant de discuter avec les autres routeurs.
     */
    void initRouteur();
    
    //! Initialise les threads.
    /*!
     Initialise et lance les threads permettant de gérer le routeur. 
     */
	void initThreads();
    
    // TODO: A compléter...
    void communicationServeur();
    
    //! Envoie un paquet à l'adresse du destinataire.
    /*!
     \param message le paquet qui sera envoyé au destinataire.
     \param adresseDest l'adresse du destinataire. 
     */
	void envoiePaquet(char * message, struct sockaddr* adresseDest);
    
    //! Recoit et traite tous les paquets qui sont envoyés au routeur.
	void recoitPaquet();
    
    //! Parse et traite le paquet envoyés au routeur.
    /*!
     \param reponseServeur le paquet à analyser.
     */
    void parseReponseServeur(char *reponseServeur);
    
    //! Retourne vrai si le routeur possède toutes les adresses de ses routeurs voisins, faux sinon.
    /*!
     \return  Vrai si le routeur possède toutes les adresse de ses routeurs voisins, faux sinon.
     */
	bool adressesVoisinsPleine();
    
    void notification(char *notification);
	
    
	//! Gere les envoi des paquets par le routeur.
    /*!
     \param arg 
     */
	static void* runEnvoie(void *arg);
    
    //! Gere la reception des paquets au routeur.
    /*!
     \param arg 
     */
	static void* runRecoit(void *arg);
    
    //! Permet d'attendre que l'utilisateur entre un message à envoyer à un autre routeur.
    /*!
     \param arg 
     */
	static void* runEnvoieMessage(void *arg);
    
    
    //! Retourne l'adresse du serveur.
    /*!
     \return L'adresse du serveur.
     */
	struct sockaddr* getAdresseServeur();
    
    //! Retourne l'adresse du processus de perte de paquet.
    /*!
     \return L'adresse du processus de perte de paquet.
     */
    struct sockaddr* getAdresseProcessusPerte();
    
    //! Retourne la date à laquelle le paquet a été envoyé.
    /*!
     \param heure La date à laquelle le paquet a été envoyé.
     */
    void getHeure(char * heure);
    
    //! Retourne l'id du routeur.
    /*!
     \return L'id du routeur.
     */
    int getIdRouteur();
    
    //! Retourne le tableau faisant la correspondance entre les adresses et les numéro des routeurs.
    /*!
     \return Le tableau faisant la correspondance entre les adresses et les numéro des routeurs.
     */
    map<int,Adresse> getAdressesVoisins();
    
    //! Retourne la table de routage du routeur.
    /*!
     \return La table de routage du routeur.
     */
    TableRoutage * getTableRoutage();
};



